using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using ComTypes = System.Runtime.InteropServices.ComTypes;
using System.Threading;
using System.Diagnostics;
using Microsoft.Win32.SafeHandles;

namespace MacomberMap.Common.Internals
{
    /// <summary>
    /// This class provides details of CPU and memory usage on the current process    
    /// Adapted from http://www.philosophicalgeek.com/2009/01/03/determine-cpu-usage-of-current-process-c-and-c/
    /// </summary>
    public static class MM_Process_Details
    {
    //    #region Imports
    //    [DllImport("kernel32.dll", SetLastError = true)]
    //    private static extern bool GetSystemTimes(out System.Runtime.InteropServices.ComTypes.FILETIME lpIdleTime, out ComTypes.FILETIME lpKernelTime, out ComTypes.FILETIME lpUserTime);

    //    [DllImport("kernel32.dll", SetLastError = true)]
    //    private static extern SafeFileHandle CreateFile(String pipeName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplate);

    //    [DllImport("psapi.dll", SetLastError = true)]
    //    static extern bool GetProcessMemoryInfo(IntPtr hProcess, out PROCESS_MEMORY_COUNTERS counters, uint size);

    //    [DllImport("kernel32.dll")]
    //    private static extern IntPtr GetCurrentProcess();

    //    [StructLayout(LayoutKind.Sequential, Size = 40)]
    //    private struct PROCESS_MEMORY_COUNTERS
    //    {
    //        public uint cb;
    //        public uint PageFaultCount;
    //        public int PeakWorkingSetSize;
    //        public int WorkingSetSize;
    //        public int QuotaPeakPagedPoolUsage;
    //        public int QuotaPagedPoolUsage;
    //        public int QuotaPeakNonPagedPoolUsage;
    //        public int QuotaNonPagedPoolUsage;
    //        public int PagefileUsage;
    //        public int PeakPagefileUsage;
    //    }

    //    #endregion

    //    #region Variable declarations
    //    /// <summary>The previous system kernel usage</summary>
    //    private static ComTypes.FILETIME _prevSysKernel;

    //    /// <summary>The previous system user usage</summary>
    //    private static ComTypes.FILETIME _prevSysUser;

    //    private static TimeSpan _prevProcTotal;
    //    private static Int16 _cpuUsage;
    //    private static DateTime _lastRun;
    //    private static long _runCount;
    //    private static long _lastWorkingSet;
    //    #endregion

    //    #region Initialization
    //    /// <summary>
    //    /// Initialize our CPU monitoring system
    //    /// </summary>
    //    public static void Initialize()
    //    {
    //        _cpuUsage = -1;
    //        _lastRun = DateTime.MinValue;
    //        _prevSysUser.dwHighDateTime = _prevSysUser.dwLowDateTime = 0;
    //        _prevSysKernel.dwHighDateTime = _prevSysKernel.dwLowDateTime = 0;
    //        _prevProcTotal = TimeSpan.MinValue;
    //        _runCount = 0;
    //    }
    //    #endregion


    //    #region CPU usage retrieval

    //    /// <summary>
    //    /// Determine the current CPU usage in percent
    //    /// </summary>
    //    /// <param name="WorkingSet">The working set</param>
    //    /// <returns></returns>
    //    public static short GetCPUUsage(out long WorkingSet)
    //    {
    //        //Determine our current process
    //        IntPtr CurrentProcess = GetCurrentProcess();
    //        PROCESS_MEMORY_COUNTERS memoryCounters;
    //        memoryCounters.cb = 40;

    //        short cpuCopy = _cpuUsage;
    //        if (Interlocked.Increment(ref _runCount) == 1)
    //        {
    //            if (!EnoughTimePassed)
    //            {
    //                Interlocked.Decrement(ref _runCount);
    //                WorkingSet = _lastWorkingSet;
    //                return cpuCopy;
    //            }

    //            ComTypes.FILETIME sysIdle, sysKernel, sysUser;
    //            TimeSpan procTime;
    //            procTime = TimeSpan.FromSeconds(2);

    //            if (GetProcessMemoryInfo(CurrentProcess, out memoryCounters, memoryCounters.cb))
    //                WorkingSet = _lastWorkingSet = memoryCounters.WorkingSetSize;
    //            else
    //                WorkingSet = _lastWorkingSet = GC.GetTotalMemory(false); // process.WorkingSet64;

    //            using (Process process = Process.GetCurrentProcess())
    //            {
    //                procTime = process.TotalProcessorTime;
    //                //  WorkingSet = _lastWorkingSet = process.WorkingSet64;
    //                //WorkingSet = 2;
    //            }

    //            if (!GetSystemTimes(out sysIdle, out sysKernel, out sysUser))
    //            {
    //                Interlocked.Decrement(ref _runCount);
    //                WorkingSet = _lastWorkingSet;
    //                return cpuCopy;
    //            }

    //            if (!IsFirstRun)
    //            {

    //                UInt64 sysKernelDiff = SubtractTimes(sysKernel, _prevSysKernel);
    //                UInt64 sysUserDiff = SubtractTimes(sysUser, _prevSysUser);
    //                UInt64 sysTotal = sysKernelDiff + sysUserDiff;
    //                Int64 procTotal = procTime.Ticks - _prevProcTotal.Ticks;
    //                if (sysTotal > 0)
    //                    _cpuUsage = (short)((100.0 * procTotal) / sysTotal);
    //            }

    //            _prevProcTotal = procTime;
    //            _prevSysKernel = sysKernel;
    //            _prevSysUser = sysUser;
    //            _lastRun = DateTime.Now;
    //            cpuCopy = _cpuUsage;
    //        }
    //        else
    //            WorkingSet = _lastWorkingSet;


    //        Interlocked.Decrement(ref _runCount);
    //        return cpuCopy;
    //    }
    //    /// <summary>
    //    /// Subtract two times
    //    /// </summary>
    //    /// <param name="a">Time 1</param>
    //    /// <param name="b">Time 2</param>
    //    /// <returns></returns>
    //    private static UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
    //    {
    //        UInt64 aInt = ((UInt64)(a.dwHighDateTime << 32)) | (UInt64)a.dwLowDateTime;
    //        UInt64 bInt = ((UInt64)(b.dwHighDateTime << 32)) | (UInt64)b.dwLowDateTime;
    //        return aInt - bInt;
    //    }

    //    /// <summary>
    //    /// Determine whether enough time has passed for an accurate reading
    //    /// </summary>
    //    private static bool EnoughTimePassed
    //    {
    //        get
    //        {
    //            const int minimumElapsedMS = 250;
    //            TimeSpan sinceLast = DateTime.Now - _lastRun;
    //            return sinceLast.TotalMilliseconds > minimumElapsedMS;
    //        }
    //    }

    //    /// <summary>
    //    /// Determine whether this is the first CPU run
    //    /// </summary>
    //    private static bool IsFirstRun
    //    {
    //        get { return (_lastRun == DateTime.MinValue); }
    //    }
    //    #endregion
    }
}
